package Equasion;

import java.awt.Color;
import java.awt.Graphics;
import java.util.*;
import Main.Main;


public class Equasion 
{
	String equasion;
	public ArrayList<EquasionPart> equasionList = new ArrayList<EquasionPart>();
	
	public Equasion(String equasion)
	{
		this.equasion = equasion;
		parseEquasion();
	}
	
	public void parseEquasion()
	{
		int cnt = 0;
		for(int i = 0;i<equasion.length();i++)
		{
			int beginningParenthesis = 1;
			if(equasion.charAt(i) == '(')
			{
				int j = i;
				int endParenthesis = 0;
				while(endParenthesis<beginningParenthesis)
				{
					j++;
					if(equasion.charAt(j) == '(')
						beginningParenthesis++;
					else if(equasion.charAt(j) == ')')
						endParenthesis++;
				}
				String part = equasion.substring(i+1, j);
				StringBuilder sb = new StringBuilder(equasion);
				equasion = sb.delete(i, j+1).toString();
				equasionList.add(new SubFunction(i,new Equasion(part)));
			}
		}
		String[] parts = equasion.split(" ");
		for(String part:parts)
		{
			if(part.length() > 0)
			{
				cnt++;
				if(part.charAt(0) >= '0' && part.charAt(0) <= '9' || part.charAt(0) == '.' || (part.charAt(0) == '-' && part.length() >= 2 && part.charAt(1)>='0' && part.charAt(1) <= '9'))
				{
					equasionList.add(new Constant(Integer.parseInt(part),cnt));
				}
				else if(part.charAt(0) == 'x')
				{
					equasionList.add(new Variable(part.charAt(0),cnt));
				}
				else if(part.charAt(0) == '-' && part.length() > 1)
				{
					StringBuilder sb = new StringBuilder(part);
					part = sb.deleteCharAt(0).toString();
					equasionList.add(new SubFunction(cnt, new Equasion(part + " * -1")));
				}
				else
				{
					equasionList.add(new Operator(part,cnt));
				}
			}
		}
	}
	
	public void displayEquasion()
	{
		for(EquasionPart p:equasionList)
		{
			if(p instanceof Constant)
			{
				System.out.print(((Constant) p).num);
			}
			else if (p instanceof Variable)
			{
				System.out.print(((Variable) p).Character);
			}
			else if (p instanceof Operator)
			{
				System.out.print(((Operator) p).string);
			}
			else if(p instanceof SubFunction)
			{
				System.out.print(((SubFunction) p).function);
			}
		}
		System.out.println();
	}
	
	public double calculateEquasion(double x)
	{
		double y = 0;
		ArrayList<Double> calculationArray = new ArrayList<Double>();
		ArrayList<Operator> operatorList = new ArrayList<Operator>();
		for(EquasionPart p:equasionList)
		{
			if (p instanceof Constant)
			{
				calculationArray.add((double) ((Constant) p).num);
			}
			else if (p instanceof Variable)
			{
				calculationArray.add(x);
			}
			else if (p instanceof Operator)
			{
				operatorList.add((Operator) p);
			}
			else if(p instanceof SubFunction)
			{
				calculationArray.add(((SubFunction) p).function.calculateEquasion(x));
			}
		}
		y = calculationArray.get(0);
		for(Operator o:operatorList)
		{
			if(o.requiresPreviousNum)
				y = parseOperator(o, y, calculationArray.get(operatorList.indexOf(o)+1));
			else
				y = parseOperator(o, y, calculationArray.get(operatorList.indexOf(o)));
		}
		return y;
	}
	
	public double parseOperator(Operator o,double y,Double operand)
	{
		if(o.string.equals("*"))
		{
			y *= operand;
		}
		else if(o.string.equals("/"))
		{
			y /= operand;
		}
		else if(o.string.equals("+"))
		{
			y += operand;
		}
		else if(o.string.equals("-"))
		{
			y -= operand;
		}
		else if(o.string.equals("sin"))
		{
			y = Math.sin(operand);
		}
		else if(o.string.equals("cos"))
		{
			y = Math.cos(operand);
		}
		else if(o.string.equals("^"))
		{
			y = Math.pow(y, operand);
		}
		else
		{
			System.out.println("Unrecognized operator");
		}
		return y;
	}
	
	public void drawEquasion(Graphics g,double period,int graphXSize, int graphYSize)
	{
		double lastY = -calculateEquasion(Main.xMin);
		double lastX = Main.xMin;
		for(double x = Main.xMin;x<=Main.xMax;x+=period)
		{
			double y = -calculateEquasion(x);
			if(y>=Main.yMin && y<= Main.yMax)
			{
				g.drawLine((int)(graphXSize/2 + lastX*(graphXSize/(Math.abs(Main.xMin)+Math.abs(Main.xMax)))+.5),
						   (int)(graphYSize/2+lastY*(graphYSize/(Math.abs(Main.yMin)+Math.abs(Main.yMax)))+.5),
						   (int)(graphXSize/2 + x*(graphXSize/(Math.abs(Main.xMin)+Math.abs(Main.xMax)))+.5),
						   (int)(graphYSize/2+y*(graphYSize/(Math.abs(Main.yMin)+Math.abs(Main.yMax)))+.5));
				lastX = x;
				lastY = y;
			}
		}
	}
}
